/* Copyright (c) 2013 fab-o-lab

 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
 files (the "Software"), to deal in the Software without
 restriction, including without limitation the rights to use,
 copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the
 Software is furnished to do so, subject to the following
 conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
*/
package com.fabolab;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
public class Archive {
  public static int BUFFER_SIZE = 10240;
  /** Constants for mode listing or mode extracting. */
  public static final int LIST = 0, EXTRACT = 1;

  /** Whether we are extracting or just printing TOC */
  protected int mode = LIST;

  /** The ZipFile that is used to read an archive */
  protected ZipFile zippy;

  /** The buffer for reading/writing the ZipFile data */
  protected byte[] b;
  
  static int indentLevel = -1; 
  public List<File> list = new ArrayList<File>(); 

  public void listFolder(File path) { 
    File files[]; 
    indentLevel++; 

    files = path.listFiles(); 
    
    Arrays.sort(files); 
    for (int i = 0, n = files.length; i < n; i++) { 
        for (int indent = 0; indent < indentLevel; indent++) { 
        System.out.print("  "); 
      } 
      System.out.println(files[i].toString()); 
      if (files[i].isDirectory()) { 

        listFolder(files[i]); 
      } 
      else{ 
        list.add(files[i]); 
      } 
    } 
    indentLevel--; 
  } 



 protected void createZipArchive(File archiveFile, File[] tobeZippedFiles) {
    try {
      byte buffer[] = new byte[BUFFER_SIZE];
      // Open archive file
      FileOutputStream stream = new FileOutputStream(archiveFile);
      ZipOutputStream out = new ZipOutputStream(stream);

      for (int i = 0; i < tobeZippedFiles.length; i++) {
        if (tobeZippedFiles[i] == null || !tobeZippedFiles[i].exists()
            || tobeZippedFiles[i].isDirectory())
          continue;
        System.out.println("Adding " + tobeZippedFiles[i].getName());

        // Add archive entry
        ZipEntry zipAdd = new ZipEntry(tobeZippedFiles[i].getName());
        zipAdd.setTime(tobeZippedFiles[i].lastModified());
        out.putNextEntry(zipAdd);

        // Read input & write to output
        FileInputStream in = new FileInputStream(tobeZippedFiles[i]);
        while (true) {
          int nRead = in.read(buffer, 0, buffer.length);
          if (nRead <= 0)
            break;
          out.write(buffer, 0, nRead);
        }
        in.close();
      }

      out.close();
      stream.close();
      System.out.println("Adding completed OK");
    } catch (Exception e) {
      e.printStackTrace();
      System.out.println("Error: " + e.getMessage());
      return;
    }
  }
 
 public void zipFolder(String sourceFolder, String targetName){
     listFolder(new File(sourceFolder)); 
     File files[] = new File[list.size()]; 
     files =  (File[]) list.toArray(files); 
     createZipArchive(new File(targetName), files); 

 }
  
  
  /** Construct an UnZip object. Just allocate the buffer 
 * @return */
  void UnZip() {
    b = new byte[8092];
  }

  /** Set the Mode (list, extract). */
  protected void setMode(int m) {
    if (m == LIST || m == EXTRACT)
      mode = m;
  }

  /** Cache of paths we've mkdir()ed. */
  protected SortedSet dirsMade;

  /** For a given Zip file, process each entry. */
  public void unZip(String fileName) {
    dirsMade = new TreeSet();
    try {
      zippy = new ZipFile(fileName);
      Enumeration<? extends ZipEntry> all = zippy.entries();
      while (all.hasMoreElements()) {
        getFile((ZipEntry) all.nextElement());
      }
    } catch (IOException err) {
      System.err.println("IO Error: " + err);
      return;
    }
  }

  protected boolean warnedMkDir = false;

  /**
   * Process one file from the zip, given its name. Either print the name, or
   * create the file on disk.
   */
  protected void getFile(ZipEntry e) throws IOException {
    String zipName = e.getName();
    switch (mode) {
    case EXTRACT:
      if (zipName.startsWith("/")) {
        if (!warnedMkDir)
          System.out.println("Ignoring absolute paths");
        warnedMkDir = true;
        zipName = zipName.substring(1);
      }
      // if a directory, just return. We mkdir for every file,
      // since some widely-used Zip creators don't put out
      // any directory entries, or put them in the wrong place.
      if (zipName.endsWith("/")) {
        return;
      }
      // Else must be a file; open the file for output
      // Get the directory part.
      int ix = zipName.lastIndexOf('/');
      if (ix > 0) {
        String dirName = zipName.substring(0, ix);
        if (!dirsMade.contains(dirName)) {
          File d = new File(dirName);
          // If it already exists as a dir, don't do anything
          if (!(d.exists() && d.isDirectory())) {
            // Try to create the directory, warn if it fails
            System.out.println("Creating Directory: " + dirName);
            if (!d.mkdirs()) {
              System.err.println("Warning: unable to mkdir "
                  + dirName);
            }
            dirsMade.add(dirName);
          }
        }
      }
      System.err.println("Creating " + zipName);
      FileOutputStream os = new FileOutputStream(zipName);
      InputStream is = zippy.getInputStream(e);
      int n = 0;
      while ((n = is.read(b)) > 0)
        os.write(b, 0, n);
      is.close();
      os.close();
      break;
    case LIST:
      // Not extracting, just list
      if (e.isDirectory()) {
        System.out.println("Directory " + zipName);
      } else {
        System.out.println("File " + zipName);
      }
      break;
    default:
      throw new IllegalStateException("mode value (" + mode + ") bad");
    }
  }
}